using GameBaseFramework.Base;
using GameBaseFramework.Extension;
using GameBaseFramework.FrameWorkCommand;
using GameBaseFramework.Pattern;
using GameUnityFrameWork.Resource;
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.UI;

namespace GameUnityFramework.Resource
{
    /// <summary>
    /// 用于挂载加载协程的MonoBehavior，DontDestoryOnLoad
    /// </summary>
    public class ResourceManager : MonoBehaviour, Icommand
    {
        /// <summary>
        /// 检测间隔
        /// </summary>
        const float Interval = 60.0f;
        /// <summary>
        /// 检测时间
        /// </summary>
        private float _leftTime = Interval;

        /// <summary>
        /// 定时检测
        /// 为空释放
        /// </summary>
        private void Update()
        {
            if (_leftTime < 0)
            {
                for (var i = _gameObjectList.Count - 1; i >= 0; i--)
                {
                    var go = _gameObjectList[i];
                    if (go == null)
                    {
                        Addressables.Release(go);
                        _gameObjectList.RemoveAt(i);
                    }
                }
                _leftTime = Interval;
                Resources.UnloadUnusedAssets();
                System.GC.Collect();
            }
            else
            {
                _leftTime -= Time.deltaTime;
            }
        }
        /// <summary>
        /// 对象池
        /// </summary>
        public Dictionary<string, LinkedList<GameObject>> _gameObjectPool = new Dictionary<string, LinkedList<GameObject>>();

        /// <summary>
        /// 从对象池分配对象
        /// 如果对象池里有相应的对象，实际上是同步加载的；如果没有相应的对象，实际上是异步加载的。
        /// </summary>
        /// <param name="path"></param>
        public void SpawnGameObject(string path, Vector3? Position = null, Vector3? Rotation = null, Transform parent = null, Action<GameObject> callback = null)
        {
            var position = Position ?? Vector3.zero;
            var rotation = Rotation ?? Vector3.zero;
            var quaternion = Quaternion.Euler(rotation);

            if (_gameObjectPool.TryGetValue(path, out var pool))
            {
                //防止对象池中有空的对象导致报错
                while (pool.Count > 0)
                {
                    var go = pool.Dequeue();
                    if (go != null)
                    {
                        go.SetActive(true);
                        go.transform.SetParent(parent);
                        go.transform.SetLocalPositionAndRotation(position, quaternion);
                        go.transform.localScale = Vector3.one;
                        callback?.Invoke(go);
                        return;
                    }
                }
            }

            try
            {
                //没有在对象池里找到对应的对象，需要异步生成相应的对象
                Addressables.InstantiateAsync(path, position, quaternion, parent).Completed += (handle) =>
                {
                    if (handle.Status == AsyncOperationStatus.Succeeded)
                    {
                        AddGameObject(handle.Result);
                        var go = handle.Result;
                        go.name = path;
                        go.transform.SetLocalPositionAndRotation(position, quaternion);
                        go.transform.localScale = Vector3.one;
                        callback?.Invoke(go);
                    }
                };
            }
            catch (Exception e)
            {
                DebugTool.LogException(e);
            }
        }

        /// <summary>
        /// 排查对象池里的空对象
        /// </summary>
        public void CheckGameObjectPool()
        {
            foreach (var KeyValuePair in _gameObjectPool)
            {
                var LinkedList = KeyValuePair.Value;
                var Current = LinkedList.First;
                while (Current != null)
                {
                    if (Current.Value == null)
                    {
                        LinkedList.RemoveAndMoveNext(ref Current);
                    }
                    else
                    {
                        Current = Current.Next;
                    }
                }
            }
        }

        /// <summary>
        /// 绑定实体列表
        /// </summary>
        private List<GameObject> _gameObjectList = new List<GameObject>();

        /// <summary>
        /// 记录Go的引用
        /// </summary>
        /// <param name="go"></param>
        public void AddGameObject(GameObject go)
        {
            _gameObjectList.Add(go);
        }


        /// <summary>
        /// 在对象池里预加载若干对象
        /// </summary>
        /// <param name="path"></param>
        /// <param name="Position"></param>
        /// <param name="Rotation"></param>
        /// <param name="parent"></param>
        /// <param name="callback"></param>
        public void PreLoadGameObject(string path, Vector3? Position = null, Vector3? Rotation = null, Transform parent = null, Action<GameObject> callback = null, int Count = 1)
        {
            var position = Position ?? Vector3.zero;
            var rotation = Rotation ?? Vector3.zero;
            var quaternion = Quaternion.Euler(rotation);
            for (var i = 0; i < Count; i++)
            {
                //没有在对象池里找到对应的对象，需要异步生成相应的对象
                Addressables.InstantiateAsync(path, position, quaternion, parent).Completed += (handle) =>
                {
                    if (handle.Status == AsyncOperationStatus.Succeeded)
                    {
                        var go = handle.Result;
                        go.name = path;
                        go.transform.SetLocalPositionAndRotation(position, quaternion);
                        go.transform.localScale = Vector3.one;
                        callback?.Invoke(go);
                    }
                };
            }
        }

        /// <summary>
        /// 回收对象到对象池
        /// </summary>
        public void RecycleGameObject(GameObject go, string path = "")
        {
            if (string.IsNullOrEmpty(path))
            {
                path = go.name;
            }
            if (!_gameObjectPool.TryGetValue(path, out var pool))
            {
                pool = new LinkedList<GameObject>();
                _gameObjectPool.Add(path, pool);
            }
            go.transform.SetParent(transform);
            go.SetActive(false);
            pool.Enqueue(go);
        }

        /// <summary>
        /// 释放GameObject在对象池占用的空间
        /// </summary>
        /// <param name="GameObjectName"></param>
        public void ReleaseGameObject(string GameObjectName)
        {
            if (_gameObjectPool.TryGetValue(GameObjectName, out var queue))
            {
                //释放内存，上GC标记
                foreach (var i in queue) Addressables.Release(i);
                queue.Clear();
                _gameObjectPool.Remove(GameObjectName);
            }
        }

        /// <summary>
        /// 加载场景
        /// </summary>
        /// <param name="SceneName"></param>
        /// <param name="callback"></param>
        public void LoadScene(string SceneName, Action callback = null)
        {
            StartCoroutine(LoadSceneCoroutine(SceneName, callback));
        }

        /// <summary>
        /// 加载场景
        /// 这会导致对象池里的对象被销毁，要重新检查一遍对象
        /// </summary>
        /// <param name="SceneName"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        IEnumerator LoadSceneCoroutine(string SceneName, Action callback = null)
        {
            var loadScenehandle = Addressables.LoadSceneAsync(SceneName, UnityEngine.SceneManagement.LoadSceneMode.Single);

            //进度条
            float LoadProgress;
            while (!loadScenehandle.IsDone)
            {
                LoadProgress = 0.1f + loadScenehandle.PercentComplete * 0.9f;
                yield return loadScenehandle;
            }

            //触发回调
            if (callback != null)
            {
                callback.DynamicInvoke();
            }

            //随着场景的切换，有一部分GameObject被销毁了，要从对象池里删除这些GameObject
            CheckGameObjectPool();

            //也许有其他的prefab要随着场景的切换进行一些操作
            this.SendCommand<NewSceneLoadedCommand>(new NewSceneLoadedCommand());
        }
    }

    /// <summary>
    /// 资源加载器静态类
    /// </summary>
    public static class UnityObjectManager
    {
        /// <summary>
        /// 资源管理器的实例化引用
        /// </summary>
        private static ResourceManager _mono;

        public static ResourceManager mono
        {
            get
            {
                if (_mono == null)
                {
                    var uiViewRoot = GameObject.Find("ResourceManager");
                    _mono = uiViewRoot.GetOrAddComponent<ResourceManager>();
                }
                return _mono;
            }
        }

        /// <summary>
        /// 读取Object
        /// </summary>
        public static void LoadGameObject(string Name, Transform parent = null, Action<GameObject> callback = null, Vector3? Position = null, Vector3? Rotation = null)
        {
            string path = ResourceHelper.GetFullResourcePath(Name);// 这句做完path还是path
            mono.SpawnGameObject(path, Position, Rotation, parent, callback);
        }
        
        /// <summary>
        /// 回收GameObject到对象池
        /// </summary>
        public static void RecycleGameObject(GameObject gameObject, string path)
        {
            mono.RecycleGameObject(gameObject, path);
        }

        /// <summary>
        /// 销毁
        /// </summary>
        /// <param name="gameObject"></param>
        public static void DestroyGameObject(object gameObject)
        {
            Addressables.Release(gameObject);
        }


        /// <summary>
        /// 释放GameObject对应的内存
        /// </summary>
        /// <param name="GameObjectName"></param>
        public static void ReleaseGameObjectMemory(string GameObjectName)
        {
            mono.ReleaseGameObject(GameObjectName);
        }

        /// <summary>
        /// 加载场景
        /// </summary>
        public static void LoadScene(string SceneName, Action callback = null)
        {
            mono.LoadScene(SceneName, callback);
        }

        /// <summary>
        /// 异步加载资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path"></param>
        /// <param name="callback"></param>
        public static void LoadAssetAsync<T>(this IResourceLoader self, string path, Action<T> callback) where T : UnityEngine.Object
        {
            Addressables.LoadAssetAsync<T>(path).Completed += (handle) =>
            {
                if (handle.Status == AsyncOperationStatus.Succeeded)
                {
                    callback?.Invoke(handle.Result);
                }
            };
        }

        /// <summary>
        /// InstantiateAsync
        /// </summary>
        /// <param name="self"></param>
        /// <param name="path"></param>
        /// <param name="parent"></param>
        /// <param name="callback"></param>
        public static void InstantiateAsync(this IResourceLoader self, string path, Transform parent, Action<GameObject> callback = null)
        {
            LoadGameObject(path, parent, callback);
        }
    }

    public interface IResourceLoader
    {

    }

}
